// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#include "coin2/exchange/bitflyer_futures/api_order/native_rest_async_asio_subscriber.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

#include "coin2/base/log.h"
#include "coin2/exchange/bitflyer_futures/symbology/product.h"

namespace coin2::exchange::bitflyer_futures::api_order {

void BitflyerFuturesRestAsyncAsioSubscriber::QueryBalance() {
  auto http_context = rest_client()->QueryBalance();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitflyerFuturesRestAsyncAsioSubscriber::QuerySpotBalance() {
  auto http_context = rest_client()->QuerySpotBalance();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitflyerFuturesRestAsyncAsioSubscriber::QueryPosition(const std::string& native_symbol) {
  RestParams params;
  params.set_product_code(native_symbol);
  auto http_context = rest_client()->QueryPosition(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitflyerFuturesRestAsyncAsioSubscriber::QueryOpenOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_product_code(native_symbol);
  params.set_child_order_state("ACTIVE");
  auto http_context = rest_client()->QueryOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitflyerFuturesRestAsyncAsioSubscriber::QueryAllOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_product_code(native_symbol);
  auto http_context = rest_client()->QueryOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitflyerFuturesRestAsyncAsioSubscriber::QueryFill(const std::string& native_symbol) {
  RestParams params;
  params.set_product_code(native_symbol);
  auto http_context = rest_client()->QueryFills(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void BitflyerFuturesRestAsyncAsioSubscriber::SubscribeAsync() {
  bool has_immediate = false;
  bool has_perpetual = false;
  for (const auto& native_symbol : native_symbols()) {
    if (native_symbol == "FX_BTC_JPY") {
      has_perpetual = true;
    } else if (native_symbol == "BTC_JPY") {
      has_immediate = true;
    }
  }
  if (has_immediate && has_perpetual) {
    CHECK(false) << "Can not trade immediate and perpetual at same time. ";
  }

  if (has_immediate) {
    AddPeriodicTask(
        std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::QuerySpotBalance, this),
        config_.query_account_position_period_sec(),
        "query_balance");
  } else {
    AddPeriodicTask(
        std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::QueryBalance, this),
        config_.query_account_balance_period_sec(),
        "query_balance");
  }

  const auto symbol_list = native_symbols();

  if (has_perpetual) {
    AddPeriodicTask(
        std::bind(
            &BitflyerFuturesRestAsyncAsioSubscriber::QueryPosition,
            this,
            std::placeholders::_1),
        config_.query_account_position_period_sec(),
        "query_position",
        symbol_list);
  }

  AddPeriodicTask(
      std::bind(
          &BitflyerFuturesRestAsyncAsioSubscriber::QueryOpenOrders,
          this,
          std::placeholders::_1),
      config_.query_open_orders_period_sec(),
      "query_open_orders",
      symbol_list);

  AddPeriodicTask(
      std::bind(
          &BitflyerFuturesRestAsyncAsioSubscriber::QueryAllOrders,
          this,
          std::placeholders::_1),
      config_.query_cancel_orders_period_sec(),
      "query_all_orders",
      symbol_list);

  AddPeriodicTask(
      std::bind(&BitflyerFuturesRestAsyncAsioSubscriber::QueryFill, this, std::placeholders::_1),
      config_.query_fill_period_sec(),
      "query_fill",
      symbol_list);
}

}  // namespace coin2::exchange::bitflyer_futures::api_order
